import * as THREE from 'three';
import {
  AmbientLight,
  AxesHelper,
  BoxBufferGeometry,
  BufferGeometry,
  DirectionalLight,
  Geometry,
  LineBasicMaterial,
  LineSegments,
  Material,
  Matrix4,
  Mesh,
  Texture,
  Vector3,
} from 'three';
import BaseThreeApp from '../BaseThreeApp';
import DebugInfo from '../DebugInfo';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; 

const worldCenter = new Vector3(0, 0, 0);

class _9_1MathTest extends BaseThreeApp {
  public scene: THREE.Scene;
  public camera: THREE.Camera;
  public renderer: THREE.WebGLRenderer;
  public geos: (Geometry | BufferGeometry)[] = [];
  public mats: Material[] = [];
  public texs: Texture[] = [];
  public axesScene: AxesHelper;
  public controller: OrbitControls;
  
  start() {
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(
      60,
      this.clientWidth / this.clientHeight,
      0.1,
      3000
    );

    this.renderer = new THREE.WebGLRenderer({
      canvas: this.element,
    });
    this.renderer.setDrawingBufferSize(this.clientWidth, this.clientHeight, 1);

    const dirLight = new DirectionalLight(0xffffff, 0.6);
    dirLight.position.set(100, 100, 100);
    dirLight.target.position.set(0, 0, 0);
    this.scene.add(dirLight);

    const ambient = new AmbientLight(0xffffff, 0.5);
    this.scene.add(ambient);

    const geo = new Geometry();
    this.geos.push(geo);
    for (let i = 0; i < 1000; i++) {
      geo.vertices.push(new Vector3(i * 2, 0, 2000));
      geo.vertices.push(new Vector3(i * 2, 0, -2000));
      geo.vertices.push(new Vector3(-i * 2, 0, 2000));
      geo.vertices.push(new Vector3(-i * 2, 0, -2000));
    }
    for (let j = 0; j < 1000; j++) {
      geo.vertices.push(new Vector3(2000, 0, j * 2));
      geo.vertices.push(new Vector3(-2000, 0, j * 2));
      geo.vertices.push(new Vector3(2000, 0, -j * 2));
      geo.vertices.push(new Vector3(-2000, 0, -j * 2));
    }
    const lineMat = new LineBasicMaterial({
      color: 0x182222,
      depthWrite: false,
    });
    const grid = new LineSegments(geo, lineMat);
    this.scene.add(grid);

    const material = new THREE.MeshLambertMaterial({ color: 0xffffff });
    this.mats.push(material);
    let buf: BufferGeometry = new BoxBufferGeometry(0.5, 0.5, 0.5);
    this.geos.push(buf);
    const mesh = new Mesh(buf, material);
    const axes = new AxesHelper(10);
    this.geos.push(axes.geometry);
    mesh.add(axes);
    this.scene.add(mesh);

    this.resetCamera();
    this.controller = new OrbitControls(this.camera, this.element);
    this.controller.target.copy(worldCenter);
    this.controller.update();
    this.controller.maxDistance = 2500;


    const mat1 = new THREE.MeshLambertMaterial({ color: 0xff0000 });
    this.mats.push(mat1);
    const obj1 = new Mesh(buf, mat1);
    obj1.add(new AxesHelper(5));
    this.scene.add(obj1);

    obj1.scale.set(0.5, 0.5, 0.5);
    obj1.position.set(-10, 0, 10);
    const matrix1 = new Matrix4();
    matrix1.lookAt(obj1.position, new Vector3(0, 0, 0), new Vector3(0, 1, 0));
    obj1.setRotationFromMatrix(matrix1);

    const mat2 = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
    this.mats.push(mat2);
    const obj2 = new Mesh(buf, mat2);
    obj2.add(new AxesHelper(5));
    this.scene.add(obj2);

    obj2.scale.set(0.5, 0.5, 0.5);
    obj2.position.set(10, 0, 10);
    const matrix2 = new Matrix4();
    matrix2.lookAt(new Vector3(0, 0, 0), obj1.position, new Vector3(0, 1, 0));
    obj2.lookAt(new Vector3(0, 0, 0));

    const matrix4 = new Matrix4().multiplyMatrices(matrix2, matrix1);
    console.log(matrix4);

    this.isRunning = true;
    requestAnimationFrame(this.render.bind(this));
  }

  public render(){
    if (!this.isRunning || this.element === null) {
      return;
    }
    DebugInfo.Instance.begin();
    
    this.renderer.render(this.scene, this.camera);
    DebugInfo.Instance.end();
    requestAnimationFrame(this.render.bind(this));
  }


  onresize(e: UIEvent) {
    super.onresize(e);
    console.log('onresive');
    if (this.renderer) {
      this.renderer.setDrawingBufferSize(
        this.clientWidth,
        this.clientHeight,
        1
      );
      if (this.camera && this.camera instanceof THREE.PerspectiveCamera) {
        this.camera.aspect = this.clientWidth / this.clientHeight;
        this.camera.updateProjectionMatrix();
      }
    }
  }

  protected resetCamera(){
    this.camera.position.set(50, 50,50);
    this.camera.lookAt(worldCenter);
  }

  public onkeydown(e: KeyboardEvent): any | void {
    if (e.key === 'r' || ' ') {
      this.resetCamera();
    }
  }

  destory() {
    this.geos.forEach((v) => v.dispose());
    this.geos = [];
    this.mats.forEach((v) => v.dispose());
    this.mats = [];
    this.texs.forEach((v) => v.dispose());
    this.texs = [];
    super.destory();
  }
}

export default new _9_1MathTest();
